package com.enba.boot.security.config;

import com.enba.boot.core.base.ShowBootInfo;
import com.enba.boot.redis.RedisOperator;
import com.enba.boot.security.jwt.DefaultJwtAccessDeniedHandler;
import com.enba.boot.security.jwt.DefaultJwtAuthenticationEntryPoint;
import com.enba.boot.security.jwt.DefaultJwtAuthenticationFailureHandler;
import com.enba.boot.security.jwt.DefaultJwtAuthenticationSuccessHandler;
import com.enba.boot.security.jwt.DefaultJwtLogoutSuccessHandler;
import com.enba.boot.security.jwt.JwtTokenUtils;
import com.enba.boot.security.properties.SecurityCaptchaProperties;
import com.enba.boot.security.properties.SecurityIgnoreUrlsProperties;
import com.enba.boot.security.properties.SecurityJwtProperties;
import com.enba.boot.security.properties.SecurityRedisKeyProperties;
import com.enba.boot.security.properties.SecurityUrlProperties;
import javax.annotation.PostConstruct;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.security.config.core.GrantedAuthorityDefaults;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;

@ComponentScan(basePackages = "com.enba.boot.security")
@EnableConfigurationProperties(
    value = {
      SecurityRedisKeyProperties.class,
      SecurityIgnoreUrlsProperties.class,
      SecurityCaptchaProperties.class,
      SecurityJwtProperties.class,
      SecurityUrlProperties.class
    })
public class SecurityAutoConfiguration implements ShowBootInfo {

  @ConditionalOnMissingBean(AccessDeniedHandler.class)
  @Bean
  public AccessDeniedHandler jwtAccessDeniedHandler() {
    return new DefaultJwtAccessDeniedHandler();
  }

  @ConditionalOnMissingBean(AuthenticationEntryPoint.class)
  @Bean
  public AuthenticationEntryPoint jwtAuthenticationEntryPoint() {
    return new DefaultJwtAuthenticationEntryPoint();
  }

  @ConditionalOnMissingBean(AuthenticationFailureHandler.class)
  @Bean
  public AuthenticationFailureHandler jwtAuthenticationFailureHandler() {
    return new DefaultJwtAuthenticationFailureHandler();
  }

  @ConditionalOnMissingBean(AuthenticationSuccessHandler.class)
  @Bean
  public AuthenticationSuccessHandler jwtAuthenticationSuccessHandler(
      JwtTokenUtils jwtTokenUtils,
      RedisOperator redisOperator,
      SecurityRedisKeyProperties redisKeyProperties) {

    return new DefaultJwtAuthenticationSuccessHandler(
        jwtTokenUtils, redisOperator, redisKeyProperties);
  }

  @ConditionalOnMissingBean(LogoutSuccessHandler.class)
  @Bean
  public LogoutSuccessHandler jwtLogoutSuccessHandler(
      RedisOperator redisOperator,
      SecurityRedisKeyProperties redisKeyProperties,
      JwtTokenUtils jwtTokenUtils,
      SecurityJwtProperties securityJwtProperties) {

    return new DefaultJwtLogoutSuccessHandler(
        redisOperator, redisKeyProperties, jwtTokenUtils, securityJwtProperties);
  }

  /**
   * 去掉 ROLE_ 前缀
   *
   * @return GrantedAuthorityDefaults
   */
  @Bean
  GrantedAuthorityDefaults grantedAuthorityDefaults() {
    return new GrantedAuthorityDefaults("");
  }

  @PostConstruct
  @Override
  public void showBootInfo() {
    ShowBootInfo.moduleMap.put("enba-boot-starter-security", "enba-boot-starter-security模块集成成功");
  }
}
